//
//  ZLLabel.swift
//  ZLUIKit_Example
//
//  Created by itzhaolei on 2021/8/25.
//  Copyright © 2021 CocoaPods. All rights reserved.
//

import UIKit

open class ZLLabel: UILabel {
        
    public var isSelected: Bool = false {
        didSet {
            isContinue = true
            textColor = isSelected ? textSelectedColor : textNormalColor
            backgroundColor = isSelected ? backgroundSelectedColor : backgroundNormalColor
            font = isSelected ? selectedFont : normalFont
            isContinue = false
        }
    }
    
    private var isContinue: Bool = false
    private var textNormalColor: UIColor = .black
    private var backgroundNormalColor: UIColor = .clear
    private var normalFont: UIFont = .boldSystemFont(ofSize: 15.0)
    
    public var textSelectedColor: UIColor = .black
    public var backgroundSelectedColor: UIColor = .clear
    public var selectedFont: UIFont = .boldSystemFont(ofSize: 15.0)
    
    
    public override var textColor: UIColor! {
        didSet {
            guard !isContinue else { return }
            textNormalColor = textColor
        }
    }
    open override var backgroundColor: UIColor? {
        didSet {
            guard !isContinue else { return }
            backgroundNormalColor = backgroundColor ?? .clear
        }
    }
    open override var font: UIFont! {
        didSet {
            guard !isContinue else { return }
            normalFont = font
        }
    }
    
    /// 文本布局
    public convenience init(frame: CGRect?, text: String?, font: UIFont?, textColor: UIColor?, textAlignment: NSTextAlignment?, lineBreakMode: NSLineBreakMode?, numberOfLines: Int?, action: Action?) {
        self.init(frame: frame ?? .zero)
        if text != nil {
            self.text = text
        }
        if textColor != nil {
            self.textColor = textColor
        }
        if font != nil {
            self.font = font
        }
        if textAlignment != nil {
            self.textAlignment = textAlignment ?? .left
        }
        if numberOfLines != nil {
            self.numberOfLines = numberOfLines ?? 1
        }
        if lineBreakMode != nil {
            self.lineBreakMode = lineBreakMode ?? .byWordWrapping
        }
        fixSize()
        guard let action = action else { return }
        isUserInteractionEnabled = true
        addGestureRecognizer(UITapGestureRecognizer(target: action.target, action: action.action))
        
        func fixSize() {
            guard let safeText = text, safeText != "", safeText.count > 0 else { return }
            if self.width == 0 {
                self.width = .auto
            }
            if self.height == 0 {
                self.height = .auto
            }
            if self.width == .auto || self.height == .auto {
                var size: CGSize = .zero
                if self.width == .auto && self.height == .auto {
                    size = self.text?.getSize(font: self.font, target: .size) ?? .zero
                }else {
                    if self.width == .auto {
                        size = self.text?.getSize(font: self.font, target: .width, limit: self.height) ?? .zero
                    }else {
                        size = self.text?.getSize(font: self.font, target: .height, limit: self.width) ?? .zero
                    }
                }
                self.width = size.width
                self.height = size.height
            }
        }
    }
    
    /// 富文本布局
    public convenience init(frame: CGRect?, attributedText: NSAttributedString?, action: Action?) {
        self.init(frame: frame ?? .zero)
        if attributedText != nil {
            self.attributedText = attributedText
        }
        self.numberOfLines = 0
        self.lineBreakMode = .byTruncatingTail
        fixSize()
        guard let action = action else { return }
        isUserInteractionEnabled = true
        addGestureRecognizer(UITapGestureRecognizer(target: action.target, action: action.action))
        
        func fixSize() {
            guard let safeText = attributedText, safeText != .init(), safeText.string.count > 0 else { return }
            if self.width == 0 {
                self.width = .auto
            }
            if self.height == 0 {
                self.height = .auto
            }
            if self.width == .auto || self.height == .auto {
                var size: CGSize = .zero
                if self.width == .auto && self.height == .auto {
                    size = Self.getSize(attributedText: self.attributedText ?? .init(), target: .size)
                }else {
                    if self.width == .auto {
                        size = Self.getSize(attributedText: self.attributedText ?? .init(), target: .width, limit: self.height)
                    }else {
                        size = Self.getSize(attributedText: self.attributedText ?? .init(), target: .height, limit: self.width)
                    }
                }
                self.width = size.width
                self.height = size.height
            }
        }
    }
    
}

public extension CGFloat {
    
    static var auto: CGFloat = 0
    
}

public extension ZLLabel {
    
    /// 填充文本时要修复的尺寸
    enum Fix {
        case size, width, height
    }
    
    func fill(text: String, fix: Fix) {
        numberOfLines = 0
        self.text = text
        lineBreakMode = .byTruncatingTail
        var limitSize: CGSize = .zero
        if fix == .width {
            limitSize = .init(width: CGFloat(MAXFLOAT), height: height)
        }else if (fix == .height) {
            limitSize = .init(width: width, height: CGFloat(MAXFLOAT))
        }else {
            limitSize = .init(width: CGFloat(MAXFLOAT), height: CGFloat(MAXFLOAT))
        }
        let size = ((self.text ?? "") as NSString).boundingRect(with: limitSize, options: .usesLineFragmentOrigin, attributes: [.font : (self.font ?? .systemFont(ofSize: 17))], context: nil).size
        if fix == .width {
            self.width = size.width
        }else if (fix == .height) {
            self.height = size.height
        }else {
            self.width = size.width
            self.height = size.height
        }
        guard let _ = font else {
            #if DEBUG
            print("⚠️文本计算出错：\n-[\(self.text ?? "")]\n因UIFont为空导致计算结果略有出入，请仔细核对后进行调整，避免影响UI紊乱")
            #endif
            return
        }
    }
    
    /// 将富文本填充至控件
    ///
    /// 内部会进行一些优化
    ///     - 自动调整 numberOfLines = 0
    ///     - lineBreakMode = byTruncatingTail
    ///     - 自动调整要修复的目标尺寸
    /// - Parameters:
    ///   - attributedText: 富文本
    ///   - fix: 自动调整的目标
    func fill(attributedText: NSAttributedString, fix: Fix) {
        self.attributedText = attributedText
        numberOfLines = 0
        lineBreakMode = .byTruncatingTail
        var limit: CGFloat = CGFloat(MAXFLOAT)
        if fix == .width {
            limit = height
        }else if (fix == .height) {
            limit = width
        }
        let size = Self.getSize(attributedText: attributedText, target: fix, limit: limit)
        if fix == .width {
            self.width = size.width
        }else if (fix == .height) {
            self.height = size.height
        }else {
            self.width = size.width
            self.height = size.height
        }
    }
    
}

public extension ZLLabel {
    
    /// 要获取的目标
    typealias Target = Fix
    /// 计算富文本尺寸值
    /// - Parameters:
    ///   - attributedText: 富文本
    ///   - target: 要获取的目标，该目标一定要Returns返回的使用价值相对应
    ///   - limit: 限制条件：例如想要获取宽的值，就填写对高的限制，依次类推
    /// - Returns: 处理下文
    static func getSize(attributedText: NSAttributedString, target: Target, limit: CGFloat = CGFloat(MAXFLOAT)) -> CGSize {
        var limitSize: CGSize? = nil
        if target == .width {
            limitSize = .init(width: CGFloat(MAXFLOAT), height: limit)
        }else if (target == .height) {
            limitSize = .init(width: limit, height: CGFloat(MAXFLOAT))
        }else {
            limitSize = .init(width: CGFloat(MAXFLOAT), height: CGFloat(MAXFLOAT))
        }
        let label = UILabel(frame: .init(x: 0, y: 0, width: limitSize?.width ?? 0, height: limitSize?.height ?? 0))
        label.numberOfLines = 0
        label.attributedText = attributedText
        label.lineBreakMode = .byTruncatingTail
        label.sizeToFit()
        return label.frame.size
    }
    
}
